/*
 * Copyright (c) 2009-2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALKES_CLASS_ID_H_INCLUDED_
#define ALKES_CLASS_ID_H_INCLUDED_

namespace alkes {

typedef void* ClassID;

struct NullClass {
    static bool isInstanceOf(const alkes::ClassID /*classid*/)
    {
        return false;
    }
};

#define AL_DECLARE_ROOT_CLASS(name) AL_DECLARE_CLASS(name, NullClass)

#define AL_DECLARE_CLASS(name, parent)                  \
    public:                                             \
        static const alkes::ClassID classID() {         \
            static int class_id = 0;                    \
            return &class_id;                           \
        }                                               \
        static const char* className() {                \
            const static char* my_name = #name;         \
            return my_name;                             \
        }                                               \
        virtual const char* getClassName() const {      \
            return className();                         \
        }                                               \
        virtual const alkes::ClassID getClassID() const {\
            return classID();                           \
        }                                               \
        virtual bool isInstanceOf(const alkes::ClassID classid) const{\
            return classid == classID()                 \
                   ? true                               \
                   : parent::isInstanceOf(classid);     \
        }

///@cond

template<class T>
struct remove_pointer;

template<class T>
struct remove_pointer<T*> {
    typedef T type;
};

///@endcond

template<class T, class U>
inline T restrict_cast(U p)
{
    if (!p || !p->isInstanceOf(remove_pointer<T>::type::classID()))
        return 0;

    return static_cast<T>(p);
}

}

#endif
